﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace DesignParttenSamples
{
    public interface ITimeProvider
    {
        DateTime CurrentDate { get; }
    }

    public class CustomTimeProvider : ITimeProvider
    {
        public DateTime CurrentDate
        {
            get { return DateTime.Now; }
        }
    }


    public class Assembler
    {
        static Dictionary<Type, Type> dictionary = new Dictionary<Type, Type>();

        static Assembler()
        {
            dictionary.Add(typeof(ITimeProvider), typeof(CustomTimeProvider));
        }

        public object Create(Type type)
        {
            if (type == null || !dictionary.ContainsKey(type))
                throw new NullReferenceException("type");

            return Activator.CreateInstance(dictionary[type]);
        }

        public T Create<T>()
        {
            return (T)Create(typeof(T));
        }
    }

    public class ConstructorClient
    {
        private readonly ITimeProvider timeProvider;
        public ConstructorClient(ITimeProvider timeProvider)
        {
            this.timeProvider = timeProvider;
            Trace.WriteLine($"CurrentDate:{timeProvider.CurrentDate}");
        }


    }

    public class SetterClient
    {
        public ITimeProvider TimeProvider { get; set; }
    }

    public interface IObjectWithTimeProvider
    {
        ITimeProvider TimeProvider { get; set; }
    }

    public class InterfaceClient : IObjectWithTimeProvider
    {
        public ITimeProvider TimeProvider { get; set; }
    }


    public class GenericClient<T> : ITimeProvider where T : ITimeProvider
    {
        public T Provider { get; set; }

        public DateTime CurrentDate
        {
            get { return Provider.CurrentDate; }
        }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public class DecoratorAttribute : Attribute 
    {
        public readonly object Injector;
        private readonly Type type;

        public DecoratorAttribute(Type type)
        {
            if (type == null)
                throw new ArgumentNullException("type");

            this.type = type;
            Injector = (new Assembler()).Create(this.type);
        }

        public Type Type
        {
            get
            {
                return this.type;
            }
        }
    }


    //TODO:尚未完全掌握
    public static class AttributeHelper {
        public static T Injector<T>(object target) where T:class
        {
            if (target == null)
                throw new ArgumentNullException(nameof(target));

            return (T)(((DecoratorAttribute[])target.GetType().GetCustomAttributes(typeof(DecoratorAttribute), true))
                .Where(x => x.Type == typeof(T))
                .FirstOrDefault()
                .Injector);
        }
    }

    [Decorator(typeof(ITimeProvider))]
    public class AttributeClient
    {
        public int GetYear()
        {
            var provider = AttributeHelper.Injector<ITimeProvider>(this);
            return provider.CurrentDate.Year;
        }

    }
}
